/* jQuery-based Options logic with Enhanced UI, Copy and Sort features */
(function () {
  // ---------- Helpers ----------
  const safeJSONParse = (text, fallback = {}) => {
    if (!text || !text.trim()) return fallback;
    try { return JSON.parse(text); } catch { return fallback; }
  };
  const splitList = (text) => (text || "").split(",").map(s => s.trim()).filter(Boolean);
  const pad = (n) => (n < 10 ? "0" + n : "" + n);
  const nowTs = () => {
    const d = new Date();
    return `${d.getFullYear()}${pad(d.getMonth()+1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
  };

  // Toast notification system
  function showToast(message, type = 'success', duration = 3000) {
    const toast = $(`
      <div class="toast ${type}">
        <div style="display: flex; align-items: center; gap: 8px;">
          <span>${type === 'success' ? '✅' : type === 'error' ? '❌' : type === 'warning' ? '⚠️' : 'ℹ️'}</span>
          <span>${message}</span>
        </div>
      </div>
    `);
    
    $('body').append(toast);
    
    // Show toast
    setTimeout(() => toast.addClass('show'), 100);
    
    // Hide toast
    setTimeout(() => {
      toast.removeClass('show');
      setTimeout(() => toast.remove(), 300);
    }, duration);
  }

  // Form validation helpers
  function validateField($field, isValid, errorMessage = '') {
    $field.removeClass('form-error form-success');
    if (isValid) {
      $field.addClass('form-success');
    } else {
      $field.addClass('form-error');
      if (errorMessage) {
        showToast(errorMessage, 'error');
      }
    }
    return isValid;
  }
  
  function downloadText(filename, text) {
    const blob = new Blob([text], { type: "application/json;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    setTimeout(() => {
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    }, 0);
  }
  
  function genId() {
    return `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
  }
  
  function normalizeRule(r) {
    const rule = { ...(r || {}) };
    if (!rule.id) rule.id = genId();
    if (typeof rule.enabled !== "boolean") rule.enabled = true;
    rule.name = rule.name || "";
    rule.group = rule.group || "";
    rule.match = rule.match || { type: "string", value: "", methods: [] };
    rule.match.type = rule.match.type === "regex" ? "regex" : "string";
    rule.match.value = String(rule.match.value || "");
    rule.match.methods = Array.isArray(rule.match.methods) ? rule.match.methods.map(m => String(m || "").toUpperCase()).filter(Boolean) : [];
    rule.action = rule.action || { type: "modifyRequest", config: {} };
    if (!["modifyRequest", "modifyResponse", "mockResponse"].includes(rule.action.type)) {
      rule.action.type = "modifyRequest";
    }
    rule.action.config = rule.action.config || {};
    return rule;
  }
  
  function keyOfRule(r) {
    return [
      String(r.name || ""),
      String(r.match?.type || "string"),
      String(r.match?.value || ""),
      String(r.action?.type || "modifyRequest")
    ].join("|");
  }

  function bg(msg) {
    return new Promise((resolve) => {
      try {
        chrome.runtime.sendMessage(msg, (resp) => resolve(resp));
      } catch (e) {
        resolve({ ok: false, error: e?.message || "sendMessage failed" });
      }
    });
  }
  
  const api = {
    getState: () => bg({ type: "getState" }),
    setEnabled: (enabled) => bg({ type: "setEnabled", enabled }),
    saveRule: (rule) => bg({ type: "saveRule", rule }),
    deleteRule: (id) => bg({ type: "deleteRule", id }),
    toggleRule: (id, enabled) => bg({ type: "toggleRule", id, enabled }),
    saveRules: (rules) => bg({ type: "saveRules", rules })
  };

  function defaultRule() {
    return {
      id: "",
      name: "",
      group: "",
      enabled: true,
      match: { type: "string", value: "", methods: [] },
      action: { type: "modifyRequest", config: {} }
    };
  }
  
  function normalizeActionConfig(actionType, cfg) {
    const base = cfg || {};
    const req = base.request || {};
    const resp = base.response || {};
    return {
      request: {
        urlReplace: req.urlReplace ? {
          from: String(req.urlReplace.from ?? ""),
          to: String(req.urlReplace.to ?? ""),
          isRegex: !!req.urlReplace.isRegex
        } : undefined,
        headers: (req.headers && (req.headers.set || req.headers.remove)) ? {
          set: req.headers.set || {},
          remove: req.headers.remove || []
        } : undefined,
        body: req.body ? {
          mode: req.body.mode === "replace" ? "replace" : "regexReplace",
          find: String(req.body.find ?? ""),
          replace: String(req.body.replace ?? "")
        } : undefined
      },
      response: {
        headers: (resp.headers && (resp.headers.set || resp.headers.remove)) ? {
          set: resp.headers.set || {},
          remove: resp.headers.remove || []
        } : undefined,
        body: resp.body ? {
          mode: resp.body.mode === "replace" ? "replace" : "regexReplace",
          find: String(resp.body.find ?? ""),
          replace: String(resp.body.replace ?? "")
        } : undefined
      }
    };
  }

  $(function () {
    // Cache elements
    const $enabled = $("#enabledSwitch");
    const $search = $("#searchInput");
    const $groupFilter = $("#groupFilter");
    const $addRule = $("#addRuleBtn");
    const $importBtn = $("#importBtn");
    const $exportBtn = $("#exportBtn");
    const $importFile = $("#importFile");
    const $summary = $("#summary");
    const $tbody = $("#rulesTbody");
    const $previewModal = $("#previewModal");
    const $previewContent = $("#previewContent");

    // Form fields
    const f = {
      id: $("#ruleId"),
      name: $("#ruleName"),
      group: $("#ruleGroup"),
      matchType: $("#matchType"),
      matchValue: $("#matchValue"),
      matchMethods: $("#matchMethods"),
      actionType: $("#actionType"),
      reqUrlFrom: $("#reqUrlFrom"),
      reqUrlTo: $("#reqUrlTo"),
      reqUrlIsRegex: $("#reqUrlIsRegex"),
      reqHeadersSet: $("#reqHeadersSet"),
      reqHeadersRemove: $("#reqHeadersRemove"),
      reqBodyMode: $("#reqBodyMode"),
      reqBodyFind: $("#reqBodyFind"),
      reqBodyReplace: $("#reqBodyReplace"),
      respHeadersSet: $("#respHeadersSet"),
      respHeadersRemove: $("#respHeadersRemove"),
      respBodyMode: $("#respBodyMode"),
      respBodyFind: $("#respBodyFind"),
      respBodyReplace: $("#respBodyReplace"),
      mockStatus: $("#mockStatus"),
      resetBtn: $("#resetForm"),
      saveBtn: $("#saveRuleBtn"),
      previewBtn: $("#previewConfig")
    };

    let state = { enabled: true, rules: [] };
    let filter = { q: "", group: "" };

    // Initialize collapsible sections
    function initCollapsibles() {
      $('.collapsible-header').on('click', function() {
        const $collapsible = $(this).parent();
        $collapsible.toggleClass('expanded');
      });
    }

    // Initialize drag and drop sorting
    let sortableInstance = null;
    function initSortable() {
      if (typeof SimpleSortable !== 'undefined' && $tbody[0]) {
        // Destroy existing instance
        if (sortableInstance) {
          sortableInstance.destroy();
        }
        
        sortableInstance = new SimpleSortable($tbody[0], {
          handle: '.drag-handle',
          ghostClass: 'sortable-ghost',
          onEnd: async function(evt) {
            const rules = [...state.rules];
            const movedRule = rules.splice(evt.oldIndex, 1)[0];
            rules.splice(evt.newIndex, 0, movedRule);
            
            const resp = await api.saveRules(rules);
            if (resp?.ok) {
              await refresh();
              showToast('规则排序已保存', 'success');
            } else {
              showToast('排序保存失败', 'error');
              await refresh(); // 恢复原状态
            }
          }
        });
        
        // Initialize the sortable
        sortableInstance.init();
      }
    }

    async function loadState() {
      const resp = await api.getState();
      if (resp?.ok) state = resp.data;
      else state = { enabled: true, rules: [] };
    }

    function renderGroups() {
      const groups = new Set([""]);
      (state.rules || []).forEach(r => groups.add(r.group || ""));
      const arr = Array.from(groups.values());
      $groupFilter.empty();
      arr.forEach(g => {
        $("<option></option>").val(g).text(g ? `📁 ${g}` : "📁 全部分组").appendTo($groupFilter);
      });
      $groupFilter.val(filter.group);
    }

    function getActionTypeIcon(type) {
      switch(type) {
        case 'modifyRequest': return '🔄';
        case 'modifyResponse': return '📝';
        case 'mockResponse': return '🎭';
        default: return '❓';
      }
    }

    function getMatchTypeText(type) {
      return type === 'regex' ? '🔍 正则' : '🔤 字符串';
    }

    function renderTable() {
      const q = (filter.q || "").toLowerCase();
      const g = filter.group || "";
      const rows = (state.rules || []).filter(r => {
        if (g && (r.group || "") !== g) return false;
        if (!q) return true;
        const name = (r.name || "").toLowerCase();
        const mv = (r.match?.value || "").toLowerCase();
        const grp = (r.group || "").toLowerCase();
        return name.includes(q) || mv.includes(q) || grp.includes(q);
      });

      $tbody.empty();

      rows.forEach((r, index) => {
        const $tr = $("<tr></tr>").attr('data-rule-id', r.id);

        // Drag handle
        const $tdDrag = $('<td class="nowrap"></td>');
        const $dragHandle = $('<span class="drag-handle">⋮⋮</span>');
        $tdDrag.append($dragHandle);

        // Status
        const $tdStatus = $('<td class="nowrap"></td>');
        // const $status = $(`<span class="rule-status ${r.enabled ? 'enabled' : 'disabled'}"></span>`);
        // $status.text(r.enabled ? '✅ 启用' : '⏸️ 禁用');
        const $toggle = $('<input type="checkbox" style="margin-left: 8px;"/>').prop("checked", !!r.enabled);
        $toggle.on("change", async function () {
          await api.toggleRule(r.id, $toggle.prop("checked"));
          await refresh();
        });
        $tdStatus.append($toggle);

        // Name
        const $tdName = $("<td></td>");
        const $nameSpan = $('<span></span>').text(r.name || "未命名规则");
        if (r.group) {
          const $groupTag = $('<br/><small style="color: var(--text-muted); margin-left: 8px;"></small>').text(`[${r.group}]`);
          $nameSpan.append($groupTag);
        }
        $tdName.append($nameSpan);

        // Group
        // const $tdGroup = $("<td></td>").text(r.group || "-");

        // Match
        const $tdMatch = $("<td></td>");
        const matchText = `${getMatchTypeText(r.match?.type)}: ${r.match?.value || ""}`;
        $tdMatch.text(matchText);
        if (r.match?.methods && r.match.methods.length > 0) {
          const $methods = $('<small style="display: block; color: var(--text-muted);"></small>').text(`方法: ${r.match.methods.join(', ')}`);
          $tdMatch.append($methods);
        }

        // Action
        const $tdAction = $("<td></td>");
        const actionText = `${getActionTypeIcon(r.action?.type)} ${r.action?.type || 'modifyRequest'}`;
        $tdAction.text(actionText);

        // Operations
        const $tdOps = $('<td class="nowrap"></td>');
        
        const $btnEdit = $('<button type="button" class="btn btn-sm">✏️ 编辑</button>').on("click", function () {
          fillForm(r);
          // 滚动到编辑区域
          $('aside.card')[0].scrollIntoView({ behavior: 'smooth' });
        });
        
        const $btnCopy = $('<button type="button" class="btn btn-sm">📋 复制</button>').on("click", async function () {
          $(this).addClass('loading');
          const copied = { ...r };
          delete copied.id; // 让系统生成新ID
          copied.name = `${copied.name} - 副本`;
          copied.enabled = true;
          
          const resp = await api.saveRule(copied);
          $(this).removeClass('loading');
          
          if (resp?.ok) {
            await refresh();
            // 编辑新复制的规则
            const newRule = (resp.data.rules || []).slice(-1)[0];
            if (newRule) fillForm(newRule);
            showToast(`规则 "${copied.name}" 复制成功`, 'success');
          } else {
            showToast("复制失败", 'error');
          }
        });
        
        const $btnUp = $('<button type="button" class="btn btn-sm">⬆️</button>').on("click", async function () {
          if (index === 0) {
            showToast("已经是第一条规则", 'warning');
            return;
          }
          $(this).addClass('loading');
          const rules = [...state.rules];
          [rules[index], rules[index - 1]] = [rules[index - 1], rules[index]];
          const resp = await api.saveRules(rules);
          $(this).removeClass('loading');
          if (resp?.ok) {
            await refresh();
            showToast("规则上移成功", 'success');
          } else {
            showToast("规则上移失败", 'error');
          }
        });
        
        const $btnDown = $('<button type="button" class="btn btn-sm">⬇️</button>').on("click", async function () {
          if (index === state.rules.length - 1) {
            showToast("已经是最后一条规则", 'warning');
            return;
          }
          $(this).addClass('loading');
          const rules = [...state.rules];
          [rules[index], rules[index + 1]] = [rules[index + 1], rules[index]];
          const resp = await api.saveRules(rules);
          $(this).removeClass('loading');
          if (resp?.ok) {
            await refresh();
            showToast("规则下移成功", 'success');
          } else {
            showToast("规则下移失败", 'error');
          }
        });
        
        const $btnDel = $('<button type="button" class="btn btn-sm btn-danger">🗑️ 删除</button>').on("click", async function () {
          if (confirm(`🗑️ 确认删除规则 "${r.name || '未命名'}" 吗？\n\n此操作不可撤销！`)) {
            $(this).addClass('loading');
            const resp = await api.deleteRule(r.id);
            $(this).removeClass('loading');
            if (resp?.ok) {
              await refresh();
              clearForm();
              showToast(`规则 "${r.name || '未命名'}" 已删除`, 'success');
            } else {
              showToast("删除失败", 'error');
            }
          }
        });
        
        $tdOps.append($btnEdit).append(' ').append($btnCopy).append(' ').append($btnUp).append($btnDown).append(' ').append($btnDel);

        $tr.append($tdDrag, $tdStatus, $tdName,  $tdMatch, $tdAction, $tdOps);
        $tbody.append($tr);
      });

      $summary.text(`共 ${state.rules?.length || 0} 条规则，当前显示 ${rows.length} 条`);
      
      // 重新初始化拖拽排序
      initSortable();
    }

    function clearForm() {
      const r = defaultRule();
      f.id.val("");
      f.name.val(r.name);
      f.group.val(r.group);
      f.matchType.val(r.match.type);
      f.matchValue.val(r.match.value);
      f.matchMethods.val("");
      f.actionType.val(r.action.type);
      f.reqUrlFrom.val("");
      f.reqUrlTo.val("");
      f.reqUrlIsRegex.prop("checked", false);
      f.reqHeadersSet.val("");
      f.reqHeadersRemove.val("");
      f.reqBodyMode.val("regexReplace");
      f.reqBodyFind.val("");
      f.reqBodyReplace.val("");
      f.respHeadersSet.val("");
      f.respHeadersRemove.val("");
      f.respBodyMode.val("regexReplace");
      f.respBodyFind.val("");
      f.respBodyReplace.val("");
      f.mockStatus.val("");
      
      // 更新动作类型相关的显示
      updateActionTypeDisplay();
    }

    function fillForm(r) {
      clearForm();
      f.id.val(r.id || "");
      f.name.val(r.name || "");
      f.group.val(r.group || "");
      f.matchType.val(r.match?.type === "regex" ? "regex" : "string");
      f.matchValue.val(r.match?.value || "");
      f.matchMethods.val((r.match?.methods || []).join(","));

      const t = r.action?.type || "modifyRequest";
      f.actionType.val(t);
      const cfg = normalizeActionConfig(t, r.action?.config);

      // request
      f.reqUrlFrom.val(cfg.request?.urlReplace?.from || "");
      f.reqUrlTo.val(cfg.request?.urlReplace?.to || "");
      f.reqUrlIsRegex.prop("checked", !!cfg.request?.urlReplace?.isRegex);
      f.reqHeadersSet.val(JSON.stringify(cfg.request?.headers?.set || {}, null, 2));
      f.reqHeadersRemove.val((cfg.request?.headers?.remove || []).join(","));

      f.reqBodyMode.val(cfg.request?.body?.mode || "regexReplace");
      f.reqBodyFind.val(cfg.request?.body?.find || "");
      f.reqBodyReplace.val(cfg.request?.body?.replace || "");

      // response
      f.respHeadersSet.val(JSON.stringify(cfg.response?.headers?.set || {}, null, 2));
      f.respHeadersRemove.val((cfg.response?.headers?.remove || []).join(","));
      f.respBodyMode.val(cfg.response?.body?.mode || "regexReplace");
      f.respBodyFind.val(cfg.response?.body?.find || "");
      f.respBodyReplace.val(cfg.response?.body?.replace || "");

      // mock
      f.mockStatus.val(r.action?.type === "mockResponse" ? (r.action?.config?.response?.status || 200) : "");
      
      // 更新动作类型相关的显示
      updateActionTypeDisplay();
    }

    function updateActionTypeDisplay() {
      const actionType = f.actionType.val();
      const $requestSection = $('#requestSection');
      const $responseSection = $('#responseSection');
      
      // 根据动作类型显示/隐藏相关区域
      if (actionType === 'modifyRequest') {
        $requestSection.show();
        $responseSection.hide();
      } else if (actionType === 'modifyResponse') {
        $requestSection.show();
        $responseSection.show();
      } else if (actionType === 'mockResponse') {
        $requestSection.hide();
        $responseSection.show();
      }
    }

    function collectForm() {
      const id = f.id.val() || "";
      const rule = {
        id,
        name: (f.name.val() || "").trim(),
        group: (f.group.val() || "").trim(),
        enabled: true,
        match: {
          type: f.matchType.val() === "regex" ? "regex" : "string",
          value: (f.matchValue.val() || "").trim(),
          methods: splitList(f.matchMethods.val() || "").map(s => s.toUpperCase())
        },
        action: {
          type: f.actionType.val()
        }
      };

      const request = {};
      // url replace
      if (f.reqUrlFrom.val() || f.reqUrlTo.val()) {
        request.urlReplace = {
          from: f.reqUrlFrom.val(),
          to: f.reqUrlTo.val(),
          isRegex: !!f.reqUrlIsRegex.prop("checked")
        };
      }
      // headers
      const reqSet = safeJSONParse(f.reqHeadersSet.val(), {});
      const reqRemove = splitList(f.reqHeadersRemove.val());
      if (Object.keys(reqSet).length || reqRemove.length) {
        request.headers = { set: reqSet, remove: reqRemove };
      }
      // body
      if (f.reqBodyFind.val() || f.reqBodyReplace.val()) {
        request.body = { mode: f.reqBodyMode.val(), find: f.reqBodyFind.val(), replace: f.reqBodyReplace.val() };
      }

      const response = {};
      const respSet = safeJSONParse(f.respHeadersSet.val(), {});
      const respRemove = splitList(f.respHeadersRemove.val());
      if (Object.keys(respSet).length || respRemove.length) {
        response.headers = { set: respSet, remove: respRemove };
      }
      if (f.respBodyFind.val() || f.respBodyReplace.val()) {
        response.body = { mode: f.respBodyMode.val(), find: f.respBodyFind.val(), replace: f.respBodyReplace.val() };
      }

      const cfg = { request, response };
      if (rule.action.type === "mockResponse") {
        const status = parseInt(f.mockStatus.val() || "200", 10);
        cfg.response = cfg.response || {};
        cfg.response.status = isNaN(status) ? 200 : status;
        // 如果是mock模式且有响应体替换内容，将其作为body
        // if (f.respBodyReplace.val()) {
          // cfg.response.body = f.respBodyReplace.val();
        // }
      }
      rule.action.config = cfg;
      return rule;
    }

    function mergeRules(current, incoming, mode) {
      const curr = Array.isArray(current) ? current.map(normalizeRule) : [];
      const inc = Array.isArray(incoming) ? incoming.map(normalizeRule) : [];
      if (mode === "replace") return inc;
      
      const byId = new Map(curr.map(r => [r.id, r]));
      const byKey = new Map(curr.map(r => [keyOfRule(r), r]));
      inc.forEach(r => {
        if (byId.has(r.id)) {
          byId.set(r.id, r);
        } else {
          const k = keyOfRule(r);
          if (byKey.has(k)) {
            const old = byKey.get(k);
            byId.set(old.id, r);
            byKey.set(k, r);
          } else {
            byId.set(r.id, r);
            byKey.set(k, r);
          }
        }
      });
      return Array.from(byId.values());
    }

    async function refresh() {
      await loadState();
      $enabled.prop("checked", !!state.enabled);
      renderGroups();
      renderTable();
    }

    // Events
    $enabled.on("change", async function () {
      await api.setEnabled($enabled.prop("checked"));
      await refresh();
    });

    $search.on("input", function () {
      filter.q = $search.val() || "";
      renderTable();
    });

    $groupFilter.on("change", function () {
      filter.group = $groupFilter.val() || "";
      renderTable();
    });

    $addRule.on("click", function () {
      clearForm();
      f.name.trigger("focus");
      $('aside.card')[0].scrollIntoView({ behavior: 'smooth' });
    });

    // 动作类型变化时更新显示
    f.actionType.on('change', updateActionTypeDisplay);

    // 预览配置
    f.previewBtn.on('click', function() {
      const rule = collectForm();
      $previewContent.text(JSON.stringify(rule, null, 2));
      $previewModal.show();
    });

    $('#closePreview').on('click', function() {
      $previewModal.hide();
    });

    $previewModal.on('click', function(e) {
      if (e.target === this) {
        $previewModal.hide();
      }
    });

    // 导出
    $exportBtn.on("click", async function () {
      const resp = await api.getState();
      const rules = (resp?.ok && Array.isArray(resp.data?.rules)) ? resp.data.rules : [];
      const payload = {
        type: "api-proxy-rules",
        version: 1,
        exportedAt: new Date().toISOString(),
        rules
      };
      downloadText(`api-proxy-rules-${nowTs()}.json`, JSON.stringify(payload, null, 2));
    });

    // 导入
    $importBtn.on("click", function () {
      $importFile.val("");
      $importFile.trigger("click");
    });

    $importFile.on("change", async function () {
      const file = this.files && this.files[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = async function () {
        try {
          const text = String(reader.result || "");
          const data = safeJSONParse(text, null);
          if (!data) {
            showToast("解析失败：不是有效的 JSON 文件", 'error');
            return;
          }
          const imported = Array.isArray(data) ? data : Array.isArray(data.rules) ? data.rules : null;
          if (!imported) {
            showToast("JSON 结构不正确，应为规则数组或包含 rules 数组的对象", 'error');
            return;
          }
          const replace = confirm("📥 导入规则：\n\n✅ 确定 = 替换现有规则\n🔄 取消 = 合并规则（同名规则将被覆盖）");
          const newRules = mergeRules(state.rules || [], imported, replace ? "replace" : "merge");
          const resp = await api.saveRules(newRules);
          if (!resp?.ok) {
            showToast("导入失败", 'error');
            return;
          }
          await refresh();
          showToast(`导入完成！当前共 ${newRules.length} 条规则`, 'success', 4000);
        } catch (e) {
          showToast("导入失败：" + (e && e.message ? e.message : "未知错误"), 'error');
        }
      };
      reader.readAsText(file, "utf-8");
    });

    f.resetBtn.on("click", function () {
      if (confirm("🗑️ 确认清空当前编辑的规则吗？")) {
        clearForm();
        showToast("表单已重置", 'success');
      }
    });

    $("#ruleForm").on("submit", async function (e) {
      e.preventDefault();
      const rule = collectForm();
      
      // 表单验证
      if (!validateField(f.name, !!rule.name, "请填写规则名称")) {
        f.name.focus();
        return;
      }
      
      if (!validateField(f.matchValue, !!rule.match.value, "请填写匹配的地址或正则表达式")) {
        f.matchValue.focus();
        return;
      }
      
      // 验证正则表达式
      if (rule.match.type === 'regex') {
        try {
          new RegExp(rule.match.value);
          validateField(f.matchValue, true);
        } catch (e) {
          validateField(f.matchValue, false, "正则表达式格式错误：" + e.message);
          f.matchValue.focus();
          return;
        }
      }
      
      // 验证JSON格式
      const reqHeaders = f.reqHeadersSet.val();
      const respHeaders = f.respHeadersSet.val();
      if (reqHeaders && !safeJSONParse(reqHeaders, null)) {
        validateField(f.reqHeadersSet, false, "请求头 JSON 格式错误");
        f.reqHeadersSet.focus();
        return;
      } else if (reqHeaders) {
        validateField(f.reqHeadersSet, true);
      }
      
      if (respHeaders && !safeJSONParse(respHeaders, null)) {
        validateField(f.respHeadersSet, false, "响应头 JSON 格式错误");
        f.respHeadersSet.focus();
        return;
      } else if (respHeaders) {
        validateField(f.respHeadersSet, true);
      }
      
      // 保存规则
      f.saveBtn.addClass('loading');
      const resp = await api.saveRule(rule);
      f.saveBtn.removeClass('loading');
      
      if (!resp?.ok) {
        showToast("保存失败", 'error');
        return;
      }
      
      await refresh();
      if (!rule.id) {
        const created = (state.rules || []).slice(-1)[0];
        fillForm(created || rule);
      }
      showToast("规则保存成功！", 'success');
    });

    // Initialize
    initCollapsibles();
    updateActionTypeDisplay();
    refresh();
  });
})();